﻿using System;
using System.ComponentModel;

namespace FairyGUI.Drawing
{
	[Serializable]
	public struct RectangleF : IEquatable<RectangleF>
	{
		public static readonly RectangleF Empty;
		public float x{ get; set; }
		public float y{ get; set; }
		public float width{ get; set; }
		public float height{ get; set; }
		
		//
		// Summary:
		//     The maximum Y coordinate of the rectangle.
		public float yMax { get; set; }
		//
		// Summary:
		//     The maximum X coordinate of the rectangle.
		public float xMax { get; set; }
		//
		// Summary:
		//     The minimum Y coordinate of the rectangle.
		public float yMin { get; set; }
		//
		// Summary:
		//     The minimum X coordinate of the rectangle.
		public float xMin { get; set; }
		
		public RectangleF (float x, float y, float width, float height)
		{
			this.x = x;
			this.y = y;
			this.width = width;
			this.height = height;

			xMin = x;
			yMin = y;

			xMax = x + width;
			yMax = y + height;
		}

		public RectangleF (PointF location, SizeF size)
		{
			this.x = location.X;
			this.y = location.Y;
			this.width = size.Width;
			this.height = size.Height;
			
			xMin = x;
			yMin = y;

			xMax = x + width;
			yMax = y + height;
		}

		public static RectangleF FromLTRB (float left, float top, float right, float bottom) => new RectangleF (left, top, right - left, bottom - top);

		public static RectangleF MinMaxRect (float xmini, float ymini, float xmax, float ymax) => new RectangleF (xmini, ymini, xmax - xmini, ymax - ymini);

		[Browsable (false)]
		public PointF Location
		{
			get => new PointF (this.X, this.Y);
			set
			{
				this.X = value.X;
				this.Y = value.Y;
			}
		}

		[Browsable (false)]
		public SizeF Size
		{
			get => new SizeF (this.Width, this.Height);
			set
			{
				this.Width = value.Width;
				this.Height = value.Height;
			}
		}

		public float X
		{
			get => this.x;
			set => this.x = value;
		}

		public float Y
		{
			get => this.y;
			set => this.y = value;
		}

		public float Width
		{
			get => this.width;
			set => this.width = value;
		}

		public float Height
		{
			get => this.height;
			set => this.height = value;
		}

		[Browsable (false)] public float Left => this.X;

		[Browsable (false)] public float Top => this.Y;

		[Browsable (false)] public float Right => this.X + this.Width;

		[Browsable (false)] public float Bottom => this.Y + this.Height;

		[Browsable (false)] public bool IsEmpty => (double)this.Width <= 0.0 || (double)this.Height <= 0.0;

		public override bool Equals (object obj) => obj is RectangleF other && this.Equals (other);

		public bool Equals (RectangleF other) => this == other;

		public static bool operator == (RectangleF left, RectangleF right) => (double)left.X == (double)right.X && (double)left.Y == (double)right.Y && (double)left.Width == (double)right.Width && (double)left.Height == (double)right.Height;

		public static bool operator != (RectangleF left, RectangleF right) => !(left == right);

		public bool Contains (float x, float y) => (double)this.X <= (double)x && (double)x < (double)this.X + (double)this.Width && (double)this.Y <= (double)y && (double)y < (double)this.Y + (double)this.Height;

		public bool Contains (PointF pt) => this.Contains (pt.X, pt.Y);

		public bool Contains (RectangleF rect) => (double)this.X <= (double)rect.X && (double)rect.X + (double)rect.Width <= (double)this.X + (double)this.Width && (double)this.Y <= (double)rect.Y && (double)rect.Y + (double)rect.Height <= (double)this.Y + (double)this.Height;

		public override int GetHashCode ()
		{
			float num = this.X;
			int hashCode1 = num.GetHashCode ();
			num = this.Y;
			int hashCode2 = num.GetHashCode ();
			int h1_1 = HashHelpers.Combine (hashCode1, hashCode2);
			num = this.Width;
			int hashCode3 = num.GetHashCode ();
			int h1_2 = HashHelpers.Combine (h1_1, hashCode3);
			num = this.Height;
			int hashCode4 = num.GetHashCode ();
			return HashHelpers.Combine (h1_2, hashCode4);
		}

		public void Inflate (float x, float y)
		{
			this.X -= x;
			this.Y -= y;
			this.Width += 2f * x;
			this.Height += 2f * y;
		}

		public void Inflate (SizeF size) => this.Inflate (size.Width, size.Height);

		public static RectangleF Inflate (RectangleF rect, float x, float y)
		{
			RectangleF rectangleF = rect;
			rectangleF.Inflate (x, y);
			return rectangleF;
		}

		public void Intersect (RectangleF rect)
		{
			RectangleF rectangleF = RectangleF.Intersect (rect, this);
			this.X = rectangleF.X;
			this.Y = rectangleF.Y;
			this.Width = rectangleF.Width;
			this.Height = rectangleF.Height;
		}

		public static RectangleF Intersect (RectangleF a, RectangleF b)
		{
			float x = Math.Max (a.X, b.X);
			float num1 = Math.Min (a.X + a.Width, b.X + b.Width);
			float y = Math.Max (a.Y, b.Y);
			float num2 = Math.Min (a.Y + a.Height, b.Y + b.Height);
			return (double)num1 >= (double)x && (double)num2 >= (double)y ? new RectangleF (x, y, num1 - x, num2 - y) : RectangleF.Empty;
		}

		public bool IntersectsWith (RectangleF rect) => (double)rect.X < (double)this.X + (double)this.Width && (double)this.X < (double)rect.X + (double)rect.Width && (double)rect.Y < (double)this.Y + (double)this.Height && (double)this.Y < (double)rect.Y + (double)rect.Height;

		public static RectangleF Union (RectangleF a, RectangleF b)
		{
			float x = Math.Min (a.X, b.X);
			float num1 = Math.Max (a.X + a.Width, b.X + b.Width);
			float y = Math.Min (a.Y, b.Y);
			float num2 = Math.Max (a.Y + a.Height, b.Y + b.Height);
			return new RectangleF (x, y, num1 - x, num2 - y);
		}

		public void Offset (PointF pos) => this.Offset (pos.X, pos.Y);

		public void Offset (float x, float y)
		{
			this.X += x;
			this.Y += y;
		}

		public static implicit operator RectangleF (Rectangle r) => new RectangleF ((float)r.X, (float)r.Y, (float)r.Width, (float)r.Height);

		public override string ToString () => "{X=" + this.X.ToString () + ",Y=" + this.Y.ToString () + ",Width=" + this.Width.ToString () + ",Height=" + this.Height.ToString () + "}";
	}

	[Serializable]
	public struct PointF : IEquatable<PointF>
	{
		public static readonly PointF Empty;
		private float x;
		private float y;

		public PointF (float x, float y)
		{
			this.x = x;
			this.y = y;
		}

		[Browsable (false)] public bool IsEmpty => (double)this.x == 0.0 && (double)this.y == 0.0;

		public float X
		{
			get => this.x;
			set => this.x = value;
		}

		public float Y
		{
			get => this.y;
			set => this.y = value;
		}

		public static PointF operator + (PointF pt, Size sz) => PointF.Add (pt, sz);

		public static PointF operator - (PointF pt, Size sz) => PointF.Subtract (pt, sz);

		public static PointF operator + (PointF pt, SizeF sz) => PointF.Add (pt, sz);

		public static PointF operator - (PointF pt, SizeF sz) => PointF.Subtract (pt, sz);

		public static bool operator == (PointF left, PointF right) => (double)left.X == (double)right.X && (double)left.Y == (double)right.Y;

		public static bool operator != (PointF left, PointF right) => !(left == right);

		public static PointF Add (PointF pt, Size sz) => new PointF (pt.X + (float)sz.Width, pt.Y + (float)sz.Height);

		public static PointF Subtract (PointF pt, Size sz) => new PointF (pt.X - (float)sz.Width, pt.Y - (float)sz.Height);

		public static PointF Add (PointF pt, SizeF sz) => new PointF (pt.X + sz.Width, pt.Y + sz.Height);

		public static PointF Subtract (PointF pt, SizeF sz) => new PointF (pt.X - sz.Width, pt.Y - sz.Height);

		public override bool Equals (object obj) => obj is PointF other && this.Equals (other);

		public bool Equals (PointF other) => this == other;

		public override int GetHashCode ()
		{
			float num = this.X;
			int hashCode1 = num.GetHashCode ();
			num = this.Y;
			int hashCode2 = num.GetHashCode ();
			return HashHelpers.Combine (hashCode1, hashCode2);
		}

		public override string ToString () => "{X=" + this.x.ToString () + ", Y=" + this.y.ToString () + "}";
	}

	[Serializable]
	public struct SizeF : IEquatable<SizeF>
	{
		public static readonly SizeF Empty;
		private float width;
		private float height;

		public SizeF (SizeF size)
		{
			this.width = size.width;
			this.height = size.height;
		}

		public SizeF (PointF pt)
		{
			this.width = pt.X;
			this.height = pt.Y;
		}

		public SizeF (float width, float height)
		{
			this.width = width;
			this.height = height;
		}

		public static SizeF operator + (SizeF sz1, SizeF sz2) => SizeF.Add (sz1, sz2);

		public static SizeF operator - (SizeF sz1, SizeF sz2) => SizeF.Subtract (sz1, sz2);

		public static SizeF operator * (float left, SizeF right) => SizeF.Multiply (right, left);

		public static SizeF operator * (SizeF left, float right) => SizeF.Multiply (left, right);

		public static SizeF operator / (SizeF left, float right) => new SizeF (left.width / right, left.height / right);

		public static bool operator == (SizeF sz1, SizeF sz2) => (double)sz1.Width == (double)sz2.Width && (double)sz1.Height == (double)sz2.Height;

		public static bool operator != (SizeF sz1, SizeF sz2) => !(sz1 == sz2);

		public static explicit operator PointF (SizeF size) => new PointF (size.Width, size.Height);

		[Browsable (false)] public bool IsEmpty => (double)this.width == 0.0 && (double)this.height == 0.0;

		public float Width
		{
			get => this.width;
			set => this.width = value;
		}

		public float Height
		{
			get => this.height;
			set => this.height = value;
		}

		public static SizeF Add (SizeF sz1, SizeF sz2) => new SizeF (sz1.Width + sz2.Width, sz1.Height + sz2.Height);

		public static SizeF Subtract (SizeF sz1, SizeF sz2) => new SizeF (sz1.Width - sz2.Width, sz1.Height - sz2.Height);

		public override bool Equals (object obj) => obj is SizeF other && this.Equals (other);

		public bool Equals (SizeF other) => this == other;

		public override int GetHashCode ()
		{
			float num = this.Width;
			int hashCode1 = num.GetHashCode ();
			num = this.Height;
			int hashCode2 = num.GetHashCode ();
			return HashHelpers.Combine (hashCode1, hashCode2);
		}

		public PointF ToPointF () => (PointF)this;

		public Size ToSize () => Size.Truncate (this);

		public override string ToString () => "{Width=" + this.width.ToString () + ", Height=" + this.height.ToString () + "}";

		private static SizeF Multiply (SizeF size, float multiplier) => new SizeF (size.width * multiplier, size.height * multiplier);
	}

	[Serializable]
	public struct Size : IEquatable<Size>
	{
		public static readonly Size Empty;
		private int width;
		private int height;

		public Size (Point pt)
		{
			this.width = pt.X;
			this.height = pt.Y;
		}

		public Size (int width, int height)
		{
			this.width = width;
			this.height = height;
		}

		public static implicit operator SizeF (Size p) => new SizeF ((float)p.Width, (float)p.Height);

		public static Size operator + (Size sz1, Size sz2) => Size.Add (sz1, sz2);

		public static Size operator - (Size sz1, Size sz2) => Size.Subtract (sz1, sz2);

		public static Size operator * (int left, Size right) => Size.Multiply (right, left);

		public static Size operator * (Size left, int right) => Size.Multiply (left, right);

		public static Size operator / (Size left, int right) => new Size (left.width / right, left.height / right);

		public static SizeF operator * (float left, Size right) => Size.Multiply (right, left);

		public static SizeF operator * (Size left, float right) => Size.Multiply (left, right);

		public static SizeF operator / (Size left, float right) => new SizeF ((float)left.width / right, (float)left.height / right);

		public static bool operator == (Size sz1, Size sz2) => sz1.Width == sz2.Width && sz1.Height == sz2.Height;

		public static bool operator != (Size sz1, Size sz2) => !(sz1 == sz2);

		public static explicit operator Point (Size size) => new Point (size.Width, size.Height);

		[Browsable (false)] public bool IsEmpty => this.width == 0 && this.height == 0;

		public int Width
		{
			get => this.width;
			set => this.width = value;
		}

		public int Height
		{
			get => this.height;
			set => this.height = value;
		}

		public static Size Add (Size sz1, Size sz2) => new Size (sz1.Width + sz2.Width, sz1.Height + sz2.Height);

		public static Size Ceiling (SizeF value) => new Size ((int)Math.Ceiling ((double)value.Width), (int)Math.Ceiling ((double)value.Height));

		public static Size Subtract (Size sz1, Size sz2) => new Size (sz1.Width - sz2.Width, sz1.Height - sz2.Height);

		public static Size Truncate (SizeF value) => new Size ((int)value.Width, (int)value.Height);

		public static Size Round (SizeF value) => new Size ((int)Math.Round ((double)value.Width), (int)Math.Round ((double)value.Height));

		public override bool Equals (object obj) => obj is Size other && this.Equals (other);

		public bool Equals (Size other) => this == other;

		public override int GetHashCode () => HashHelpers.Combine (this.Width, this.Height);

		public override string ToString () => "{Width=" + this.width.ToString () + ", Height=" + this.height.ToString () + "}";

		private static Size Multiply (Size size, int multiplier) => new Size (size.width * multiplier, size.height * multiplier);

		private static SizeF Multiply (Size size, float multiplier) => new SizeF ((float)size.width * multiplier, (float)size.height * multiplier);
	}

	[Serializable]
	public struct Point : IEquatable<Point>
	{
		public static readonly Point Empty;
		private int x;
		private int y;

		public Point (int x, int y)
		{
			this.x = x;
			this.y = y;
		}

		public Point (Size sz)
		{
			this.x = sz.Width;
			this.y = sz.Height;
		}

		public Point (int dw)
		{
			this.x = (int)Point.LowInt16 (dw);
			this.y = (int)Point.HighInt16 (dw);
		}

		[Browsable (false)] public bool IsEmpty => this.x == 0 && this.y == 0;

		public int X
		{
			get => this.x;
			set => this.x = value;
		}

		public int Y
		{
			get => this.y;
			set => this.y = value;
		}

		public static implicit operator PointF (Point p) => new PointF ((float)p.X, (float)p.Y);

		public static explicit operator Size (Point p) => new Size (p.X, p.Y);

		public static Point operator + (Point pt, Size sz) => Point.Add (pt, sz);

		public static Point operator - (Point pt, Size sz) => Point.Subtract (pt, sz);

		public static bool operator == (Point left, Point right) => left.X == right.X && left.Y == right.Y;

		public static bool operator != (Point left, Point right) => !(left == right);

		public static Point Add (Point pt, Size sz) => new Point (pt.X + sz.Width, pt.Y + sz.Height);

		public static Point Subtract (Point pt, Size sz) => new Point (pt.X - sz.Width, pt.Y - sz.Height);

		public static Point Ceiling (PointF value) => new Point ((int)Math.Ceiling ((double)value.X), (int)Math.Ceiling ((double)value.Y));

		public static Point Truncate (PointF value) => new Point ((int)value.X, (int)value.Y);

		public static Point Round (PointF value) => new Point ((int)Math.Round ((double)value.X), (int)Math.Round ((double)value.Y));

		public override bool Equals (object obj) => obj is Point other && this.Equals (other);

		public bool Equals (Point other) => this == other;

		public override int GetHashCode () => HashHelpers.Combine (this.X, this.Y);

		public void Offset (int dx, int dy)
		{
			this.X += dx;
			this.Y += dy;
		}

		public void Offset (Point p) => this.Offset (p.X, p.Y);

		public override string ToString () => "{X=" + this.X.ToString () + ",Y=" + this.Y.ToString () + "}";

		private static short HighInt16 (int n) => (short)(n >> 16 & (int)ushort.MaxValue);

		private static short LowInt16 (int n) => (short)(n & (int)ushort.MaxValue);
	}

	[Serializable]
	public struct Rectangle : IEquatable<Rectangle>
	{
		public static readonly Rectangle Empty;
		private int x;
		private int y;
		private int width;
		private int height;

		public Rectangle (int x, int y, int width, int height)
		{
			this.x = x;
			this.y = y;
			this.width = width;
			this.height = height;
		}

		public Rectangle (Point location, Size size)
		{
			this.x = location.X;
			this.y = location.Y;
			this.width = size.Width;
			this.height = size.Height;
		}

		public static Rectangle FromLTRB (int left, int top, int right, int bottom) => new Rectangle (left, top, right - left, bottom - top);

		[Browsable (false)]
		public Point Location
		{
			get => new Point (this.X, this.Y);
			set
			{
				this.X = value.X;
				this.Y = value.Y;
			}
		}

		[Browsable (false)]
		public Size Size
		{
			get => new Size (this.Width, this.Height);
			set
			{
				this.Width = value.Width;
				this.Height = value.Height;
			}
		}

		public int X
		{
			get => this.x;
			set => this.x = value;
		}

		public int Y
		{
			get => this.y;
			set => this.y = value;
		}

		public int Width
		{
			get => this.width;
			set => this.width = value;
		}

		public int Height
		{
			get => this.height;
			set => this.height = value;
		}

		[Browsable (false)] public int Left => this.X;

		[Browsable (false)] public int Top => this.Y;

		[Browsable (false)] public int Right => this.X + this.Width;

		[Browsable (false)] public int Bottom => this.Y + this.Height;

		[Browsable (false)] public bool IsEmpty => this.height == 0 && this.width == 0 && this.x == 0 && this.y == 0;

		public override bool Equals (object obj) => obj is Rectangle other && this.Equals (other);

		public bool Equals (Rectangle other) => this == other;

		public static bool operator == (Rectangle left, Rectangle right) => left.X == right.X && left.Y == right.Y && left.Width == right.Width && left.Height == right.Height;

		public static bool operator != (Rectangle left, Rectangle right) => !(left == right);

		public static Rectangle Ceiling (RectangleF value) => new Rectangle ((int)Math.Ceiling ((double)value.X), (int)Math.Ceiling ((double)value.Y), (int)Math.Ceiling ((double)value.Width), (int)Math.Ceiling ((double)value.Height));

		public static Rectangle Truncate (RectangleF value) => new Rectangle ((int)value.X, (int)value.Y, (int)value.Width, (int)value.Height);

		public static Rectangle Round (RectangleF value) => new Rectangle ((int)Math.Round ((double)value.X), (int)Math.Round ((double)value.Y), (int)Math.Round ((double)value.Width), (int)Math.Round ((double)value.Height));

		public bool Contains (int x, int y) => this.X <= x && x < this.X + this.Width && this.Y <= y && y < this.Y + this.Height;

		public bool Contains (Point pt) => this.Contains (pt.X, pt.Y);

		public bool Contains (Rectangle rect) => this.X <= rect.X && rect.X + rect.Width <= this.X + this.Width && this.Y <= rect.Y && rect.Y + rect.Height <= this.Y + this.Height;

		public override int GetHashCode () => HashHelpers.Combine (HashHelpers.Combine (HashHelpers.Combine (this.X, this.Y), this.Width), this.Height);

		public void Inflate (int width, int height)
		{
			this.X -= width;
			this.Y -= height;
			this.Width += 2 * width;
			this.Height += 2 * height;
		}

		public void Inflate (Size size) => this.Inflate (size.Width, size.Height);

		public static Rectangle Inflate (Rectangle rect, int x, int y)
		{
			Rectangle rectangle = rect;
			rectangle.Inflate (x, y);
			return rectangle;
		}

		public void Intersect (Rectangle rect)
		{
			Rectangle rectangle = Rectangle.Intersect (rect, this);
			this.X = rectangle.X;
			this.Y = rectangle.Y;
			this.Width = rectangle.Width;
			this.Height = rectangle.Height;
		}

		public static Rectangle Intersect (Rectangle a, Rectangle b)
		{
			int x = Math.Max (a.X, b.X);
			int num1 = Math.Min (a.X + a.Width, b.X + b.Width);
			int y = Math.Max (a.Y, b.Y);
			int num2 = Math.Min (a.Y + a.Height, b.Y + b.Height);
			return num1 >= x && num2 >= y ? new Rectangle (x, y, num1 - x, num2 - y) : Rectangle.Empty;
		}

		public bool IntersectsWith (Rectangle rect) => rect.X < this.X + this.Width && this.X < rect.X + rect.Width && rect.Y < this.Y + this.Height && this.Y < rect.Y + rect.Height;

		public static Rectangle Union (Rectangle a, Rectangle b)
		{
			int x = Math.Min (a.X, b.X);
			int num1 = Math.Max (a.X + a.Width, b.X + b.Width);
			int y = Math.Min (a.Y, b.Y);
			int num2 = Math.Max (a.Y + a.Height, b.Y + b.Height);
			return new Rectangle (x, y, num1 - x, num2 - y);
		}

		public void Offset (Point pos) => this.Offset (pos.X, pos.Y);

		public void Offset (int x, int y)
		{
			this.X += x;
			this.Y += y;
		}

		public override string ToString () => "{X=" + this.X.ToString () + ",Y=" + this.Y.ToString () + ",Width=" + this.Width.ToString () + ",Height=" + this.Height.ToString () + "}";
	}

	internal static class HashHelpers
	{
		public static readonly int RandomSeed = Guid.NewGuid ().GetHashCode ();

		public static int Combine (int h1, int h2) => (h1 << 5 | (int)((uint)h1 >> 27)) + h1 ^ h2;
	}

	//
	// Summary:
	//     Specifies style information applied to text.
	[Flags]
	public enum FontStyle
	{
		Normal = 0,

		//
		// Summary:
		//     Normal text.
		Regular = 0,

		//
		// Summary:
		//     Bold text.
		Bold = 1,

		//
		// Summary:
		//     Italic text.
		Italic = 2,

		//
		// Summary:
		//     Underlined text.
		Underline = 4,

		//
		// Summary:
		//     Text with a line through the middle.
		Strikeout = 8,

		//
		// Summary:
		//     Bold and Italic styles applied to your texts.
		BoldAndItalic = 3
	}

	//
	// Summary:
	//     Specifies the unit of measure for the given data.
	public enum GraphicsUnit
	{
		//
		// Summary:
		//     Specifies the world coordinate system unit as the unit of measure.
		World = 0,

		//
		// Summary:
		//     Specifies the unit of measure of the display device. Typically pixels for video
		//     displays, and 1/100 inch for printers.
		Display = 1,

		//
		// Summary:
		//     Specifies a device pixel as the unit of measure.
		Pixel = 2,

		//
		// Summary:
		//     Specifies a printer's point (1/72 inch) as the unit of measure.
		Point = 3,

		//
		// Summary:
		//     Specifies the inch as the unit of measure.
		Inch = 4,

		//
		// Summary:
		//     Specifies the document unit (1/300 inch) as the unit of measure.
		Document = 5,

		//
		// Summary:
		//     Specifies the millimeter as the unit of measure.
		Millimeter = 6
	}

	public class Font
	{
		public string Name;
		public int Size;
		public FontStyle Style;
		public GraphicsUnit GraphicsUnit;

		public Font (string name, int size, FontStyle style, GraphicsUnit graphicsUnit)
		{
			Name = name;
			Size = size;
			Style = style;
			GraphicsUnit = graphicsUnit;
		}
	}

	public struct CharacterRange
	{
		private int _first;
		private int _length;

		public CharacterRange (int First, int Length)
		{
			this._first = First;
			this._length = Length;
		}

		public int First
		{
			get => this._first;
			set => this._first = value;
		}

		public int Length
		{
			get => this._length;
			set => this._length = value;
		}

		public override bool Equals (object obj)
		{
			if (obj.GetType () != typeof (CharacterRange))
				return false;
			CharacterRange characterRange = (CharacterRange)obj;
			return this._first == characterRange.First && this._length == characterRange.Length;
		}

		public static bool operator == (CharacterRange cr1, CharacterRange cr2) => cr1.First == cr2.First && cr1.Length == cr2.Length;

		public static bool operator != (CharacterRange cr1, CharacterRange cr2) => !(cr1 == cr2);

		public override int GetHashCode () => this._first << 8 + this._length;
	}
}